package com.desmond.squarecamera;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.graphics.Surface;
import ohos.agp.utils.Rect;
import ohos.app.Context;
import ohos.global.configuration.Configuration;
import ohos.media.camera.CameraKit;
import ohos.media.camera.device.Camera;
import ohos.media.camera.device.CameraAbility;
import ohos.media.camera.device.CameraInfo;
import ohos.media.camera.device.FrameConfig;
import ohos.media.camera.params.Metadata;
import ohos.multimodalinput.event.MmiPoint;
import ohos.multimodalinput.event.TouchEvent;

import static ohos.media.camera.device.Camera.FrameConfigType.FRAME_CONFIG_PREVIEW;

public class SquareCameraPreview extends ComponentContainer implements
        ComponentContainer.EstimateSizeListener,
        ComponentContainer.TouchEventListener,
        ComponentContainer.ArrangeListener {

    public static final String TAG = SquareCameraPreview.class.getSimpleName();
    private static final int INVALID_POINTER_ID = -1;

    private static final int ZOOM_OUT = 0;
    private static final int ZOOM_IN = 1;
    private static final int ZOOM_DELTA = 1;

    private static final int FOCUS_SQR_SIZE = 100;
    private static final int FOCUS_MAX_BOUND = 1000;
    private static final int FOCUS_MIN_BOUND = -FOCUS_MAX_BOUND;

    private static final double ASPECT_RATIO = 3.0 / 4.0;
    private Camera mCamera;
    private int mCameraID;
    private CameraKit mCameraKit;
    private CameraAbility mCameraAbility;

    private float mLastTouchX;
    private float mLastTouchY;

    // For scaling
    private int mMaxZoom;
    private boolean mIsZoomSupported;
    private int mActivePointerId = INVALID_POINTER_ID;
    private int mScaleFactor = 1;
//    private ScaleGestureDetector mScaleDetector;

    // For focus
    private boolean mIsFocus;
    private boolean mIsFocusReady;
    //    private Camera.Area mFocusArea;
//    private ArrayList<Camera.Area> mFocusAreas;
    private int squareLen = 0;

    private Surface previewSurface;

    public SquareCameraPreview(Context context) {
        this(context, null);
    }

    public SquareCameraPreview(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    public SquareCameraPreview(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);

        setEstimateSizeListener(this);
        setArrangeListener(this);
        setTouchEventListener(this);

    }

    @Override
    public boolean onEstimateSize(int widthEstimateConfig, int heightEstimateConfig) {

        int width = Component.EstimateSpec.getSize(widthEstimateConfig);
        int height = Component.EstimateSpec.getSize(heightEstimateConfig);

        int config;

        final boolean isPortrait = getResourceManager()
                .getConfiguration()
                .direction == Configuration.DIRECTION_VERTICAL;

        if (isPortrait) {
            squareLen = (int) (width / ASPECT_RATIO + 0.5);
            config = widthEstimateConfig;
        } else {
            squareLen = (int) (height / ASPECT_RATIO + 0.5);
            config = heightEstimateConfig;
        }

        setEstimatedSize(
                Component
                        .EstimateSpec
                        .getChildSizeWithMode(squareLen, config, EstimateSpec.NOT_EXCEED),
                Component
                        .EstimateSpec
                        .getChildSizeWithMode(squareLen, config, EstimateSpec.NOT_EXCEED)
        );

        return true;
    }

    public int getViewWidth() {
        return getWidth();
    }

    public int getViewHeight() {
        return getHeight();
    }

    public void setCamera(Camera camera, int cameraID, Surface previewSurface) {
        this.previewSurface = previewSurface;
        mCamera = camera;
        this.mCameraID = cameraID;
        mCameraKit = CameraKit.getInstance(getContext());
        String cameraId = "";

        if (camera != null) {
            String[] cameraList = mCameraKit.getCameraIds();
            for (String logicalCameraId : cameraList) {
                int faceType = mCameraKit.getCameraInfo(logicalCameraId).getFacingType();
                switch (faceType) {
                    case CameraInfo.FacingType.CAMERA_FACING_FRONT:
                        if (mCameraID == CameraInfo.FacingType.CAMERA_FACING_FRONT) {
                            cameraId = logicalCameraId;
                        }
                        break;
                    case CameraInfo.FacingType.CAMERA_FACING_BACK:
                        if (mCameraID != CameraInfo.FacingType.CAMERA_FACING_FRONT) {
                            cameraId = logicalCameraId;
                        }
                        break;
                    case CameraInfo.FacingType.CAMERA_FACING_OTHERS:
                    default:
                        break;
                }
            }

            mCameraAbility = mCameraKit.getCameraAbility(cameraId);
            if (mCameraAbility != null) {
                float[] supportedZoom = mCameraAbility.getSupportedZoom();
                //TODO 获取相机是否支持变焦，支持变焦的最大数值
            }
        }
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {

        final int action = touchEvent.getAction();
        switch (action) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                mIsFocus = true;
                MmiPoint absPoint = touchEvent.getPointerPosition(touchEvent.getIndex());
                mLastTouchX = absPoint.getX();
                mLastTouchY = absPoint.getY();

                mActivePointerId = touchEvent.getPointerId(0);

                break;
            case TouchEvent.PRIMARY_POINT_UP:
                if (mIsFocus && mIsFocusReady) {
                    handleFocus();
                }
                mActivePointerId = INVALID_POINTER_ID;
                break;
            case TouchEvent.CANCEL:
                mActivePointerId = INVALID_POINTER_ID;
                break;
            default:
                break;
        }

        return true;
    }

    private void handleZoom() {
        //TODO 设置变焦
    }

    private void handleFocus() {

        float x = mLastTouchX;
        float y = mLastTouchY;

        setFocusBound(x, y);
    }

    public void setIsFocusReady(final boolean isFocusReady) {
        mIsFocusReady = isFocusReady;
    }

    private boolean setFocusBound(float x, float y) {
        final int left = (int) (x - FOCUS_SQR_SIZE / 2);
        final int right = (int) (x + FOCUS_SQR_SIZE / 2);
        final int top = (int) (y - FOCUS_SQR_SIZE / 2);
        final int bottom = (int) (y + FOCUS_SQR_SIZE / 2);

        if (FOCUS_MIN_BOUND > left || left > FOCUS_MAX_BOUND) {
            return false;
        }
        if (FOCUS_MIN_BOUND > right || right > FOCUS_MAX_BOUND) {
            return false;
        }
        if (FOCUS_MIN_BOUND > top || top > FOCUS_MAX_BOUND) {
            return false;
        }
        if (FOCUS_MIN_BOUND > bottom || bottom > FOCUS_MAX_BOUND) {
            return false;
        }

        Rect rect = new Rect(left, top, right, bottom);

        FrameConfig.Builder frameConfigBuilder = mCamera
                .getFrameConfigBuilder(FRAME_CONFIG_PREVIEW);
        frameConfigBuilder.addSurface(previewSurface);
        FrameConfig frameConfig = frameConfigBuilder
                .setAfMode(Metadata.AfMode.AF_MODE_CONTINUOUS, rect)
                .build();
        mCamera.triggerLoopingCapture(frameConfig);

        return true;
    }

    @Override
    public boolean onArrange(int left, int top, int width, int height) {
        Component childView = getComponentAt(0);
        if (childView != null) {
            childView.arrange(0, 0, squareLen, squareLen);
        }
        return true;
    }
}
